package com.sneakxy.mybase4j.generator.core;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
	
/**
 * 类设计器
 * @author 潜行的青衣
 * @see
 */
public class ClassDesigner extends ClassType {
	
	private Permission permission = Permission.PUBLIC;
	
	private boolean interfaceClass = false;
	
	private ClassType extendsClass;
	
	private final List<ClassType> otherImports = new ArrayList<ClassType>();
	
	private final List<ClassType> implementsClass = new ArrayList<ClassType>();

	private final List<ClassField> fields = new ArrayList<ClassField>();
	
	private final List<ClassMethod> constructionMethods = new ArrayList<ClassMethod>();
	
	private final List<ClassMethod> methods = new ArrayList<ClassMethod>();
	
	private List<Annotation> annotations = new ArrayList<Annotation>();
	
	private String comment;
	
	/**
	 * @param name
	 */
	public ClassDesigner(String fullName) {
		super(fullName);
	}
	
	/**
	 * 添加构造方法
	 * @author 潜行的青衣
	 * @version
	 * @return
	 */
	public ClassMethod addConstructionMethod() {
		ClassMethod method = new ClassMethod(this.getTypeName());
		method.setConstruction(true);
		this.constructionMethods.add(method);
		return method;
	}
	
	public Annotation addAnnotation(Annotation annotation) {
		this.annotations.add(annotation);
		return annotation;
	}
	
	public ClassType addOtherImport(ClassType type) {
		this.otherImports.add(type);
		return type;
	}
	
	public ClassMethod addClassMethod(ClassMethod method) {
		methods.add(method);
		return method;
	}
	
	public ClassField addClassField(ClassField field) {
		fields.add(field);
		return field;
	}
	
	public void addClassField(List<ClassField> fields) {
		this.fields.addAll(fields);
	}
	
	public ClassField addClassField(int index, ClassField field) {
		fields.add(index, field);
		return field;
	}
	
	public void addClassField(int index, List<ClassField> fields) {
		this.fields.addAll(index, fields);
	}
	
	public void removeClassField(ClassField field) {
		this.fields.remove(field);
	}
	
	public void removeClassFields(List<ClassField> fields) {
		this.fields.removeAll(fields);
	}
	
	public ClassType addImplementsClass(ClassType type) {
		this.implementsClass.add(type);
		return type;
	}
	
	public void setComment(String comment) {
		this.comment = comment;
	}

	public void setInterfaceClass(boolean interfaceClass) {
		this.interfaceClass = interfaceClass;
	}

	public void setExtendsClass(ClassType extendsClass) {
		this.extendsClass = extendsClass;
	}

	public List<ClassType> getImplementsClass() {
		return implementsClass;
	}

	public List<ClassField> getFields() {
		return fields;
	}

	public List<ClassMethod> getConstructionMethods() {
		return constructionMethods;
	}

	public List<ClassMethod> getMethods() {
		return methods;
	}

	public List<ClassType> getOtherImports() {
		return otherImports;
	}

	public boolean isInterfaceClass() {
		return interfaceClass;
	}

	public ClassType getExtendsClass() {
		return extendsClass;
	}

	public String getComment() {
		return comment;
	}

	public Permission getPermission() {
		return permission;
	}

	public void setPermission(Permission permission) {
		this.permission = permission;
	}
	
	public void buildClass(String basePath) throws FileNotFoundException {
		StringBuilder path = new StringBuilder();
		path.append(basePath);
		if(!StringUtils.endsWith(basePath, File.separator)) {
			path.append(File.separator);
		}
		path.append(StringUtils.replace(this.getImportPackage(), ".", File.separator));
		File dir = new File(path.toString());
		
		if(!dir.exists()) {
			dir.mkdirs();
		}
		path.append(File.separator).append(this.getTypeName()).append(".java");
		File file = new File(path.toString());
		System.out.println(file.getAbsolutePath());
		this.buildClass(new FileOutputStream(new File(path.toString())));
	}
	
	public void buildClass(OutputStream os) {
		PrintWriter pw = new PrintWriter(os);
		pw.print("package ");
		pw.print(this.getImportPackage());
		pw.println(";");
		List<Type> imports = this.getImportClassType();
		List<Type> alimports = new ArrayList<Type>();
		List<TypeExt> alimportsext = new ArrayList<TypeExt>();
		//导包排序
		Collections.sort(imports, new Comparator<Type>() {

			@Override
			public int compare(Type o1, Type o2) {
				return o1.toString(false).compareTo(o2.toString(false));
			}
			
		});
		//导包
		String packageName = null;
		Iterator<Type> it = imports.iterator();
		Type type = null;
		while(it.hasNext()) {
			type = it.next();
			if(type.hasImportPackage()) {
				if(!alimports.contains(type)) {
					if(!StringUtils.equals(type.getImportPackage(), packageName)) {
						packageName = type.getImportPackage();
						pw.println();
					}
					pw.print("import ");
					pw.print(type.toString(false));
					pw.println(";");
					alimports.add(type);
					alimportsext.add(new TypeExt(type));
				} else {
					type.setHasPackage(!alimportsext.contains(new TypeExt(type)));
				}
			}
		}
		pw.println();
		//类注释
		if(StringUtils.isNotBlank(comment)) {
			pw.println(this.comment);
		}
		//注解
		Iterator<Annotation> annit = annotations.iterator();
		while(annit.hasNext()) {
			pw.append(annit.next().toString(true)).append("\r\n");
		}
		//类
		pw.print(this.permission.value());
		pw.print(" ");
		pw.print(this.isInterfaceClass() ? "interface" : "class");
		pw.print(" ");
		pw.print(this.toString(true));
		if(this.extendsClass != null) {
			pw.print(" extends ");
			pw.print(this.extendsClass.toString(true));
		}
		if(!this.implementsClass.isEmpty()) {
			pw.print(" implements ");
			Iterator<ClassType> iit = this.implementsClass.iterator();
			ClassType itype = null;
			while(iit.hasNext()) {
				itype = iit.next();
				pw.print(itype.toString(true));
				if(iit.hasNext()) {
					pw.print(", ");
				}
			}
		}
		pw.println(" {");
		pw.println();
		//字段
		Iterator<ClassField> fit = this.fields.iterator();
		ClassField field = null;
		while(fit.hasNext()) {
			field = fit.next();
			pw.println(field.toFieldString());
			pw.println();
		}
		
		//构造函数
		if(!this.constructionMethods.isEmpty()) {
			Iterator<ClassMethod> mit = this.constructionMethods.iterator();
			ClassMethod method = null;
			while(mit.hasNext()) {
				method = mit.next();
				pw.println(method.toMethodString());
			}
		}
		//其他方法
		if(!this.methods.isEmpty()) {
			Iterator<ClassMethod> mit = this.methods.iterator();
			ClassMethod method = null;
			while(mit.hasNext()) {
				method = mit.next();
				pw.println(method.toMethodString());
			}
		}
		//getter,setter方法
		fit = this.fields.iterator();
		while(fit.hasNext()) {
			field = fit.next();
			if(field.isGetter()) {
				pw.println(field.toGetterString());
			}
			if(field.isSetter()) {
				pw.println(field.toSetterString());
			}
		}
		pw.println("}");
		IOUtils.closeQuietly(pw);
	}
	
	private List<Type> getImportClassType() {
		List<Type> imports = new ArrayList<Type>();
		imports.addAll(this.otherImports);
		if(this.extendsClass != null) {
			imports.add(extendsClass);
		}
		imports.addAll(this.implementsClass);
		imports.addAll(this.annotations);
		Iterator<ClassField> fit = fields.iterator();
		ClassField field = null;
		while(fit.hasNext()) {
			field = fit.next();
			imports.addAll(field.getImportClassType());
		}
		
		Iterator<ClassMethod> mit = this.constructionMethods.iterator();
		ClassMethod method = null;
		while(mit.hasNext()) {
			method = mit.next();
			imports.addAll(method.getImportClassType());
		}
		
		mit = this.methods.iterator();
		while(mit.hasNext()) {
			method = mit.next();
			imports.addAll(method.getImportClassType());
		}
		return imports;
	}

}
